// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.util;

import gnu.trove.set.hash.THashSet;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import zombie.util.list.PZArrayUtil;

public final class Pool<PO extends IPooledObject> {
    private final Supplier<PO> m_allocator;
    private final ThreadLocal<Pool.PoolStacks> m_stacks = ThreadLocal.withInitial(Pool.PoolStacks::new);

    public Pool(Supplier<PO> allocator) {
        this.m_allocator = allocator;
    }

    public final PO alloc() {
        Supplier supplier = this.m_allocator;
        Pool.PoolStacks poolStacks = (Pool.PoolStacks)this.m_stacks.get();
        THashSet tHashSet = poolStacks.inUse;
        List list = poolStacks.released;
        IPooledObject iPooledObject;
        if (!list.isEmpty()) {
            iPooledObject = (IPooledObject)list.remove(list.size() - 1);
        } else {
            iPooledObject = (IPooledObject)supplier.get();
            if (iPooledObject == null) {
                throw new NullPointerException("Allocator returned a nullPtr. This is not allowed.");
            }

            iPooledObject.setPool(this);
        }

        iPooledObject.setFree(false);
        tHashSet.add(iPooledObject);
        return (PO)iPooledObject;
    }

    public final void release(IPooledObject item) {
        Pool.PoolStacks poolStacks = (Pool.PoolStacks)this.m_stacks.get();
        THashSet tHashSet = poolStacks.inUse;
        List list = poolStacks.released;
        if (item.getPool() != this) {
            throw new UnsupportedOperationException("Cannot release item. Not owned by this pool.");
        } else if (item.isFree()) {
            throw new UnsupportedOperationException("Cannot release item. Already released.");
        } else {
            tHashSet.remove(item);
            item.setFree(true);
            list.add(item);
            item.onReleased();
        }
    }

    public static <E> E tryRelease(E object) {
        IPooledObject iPooledObject = Type.tryCastTo(object, IPooledObject.class);
        if (iPooledObject != null && !iPooledObject.isFree()) {
            iPooledObject.release();
        }

        return null;
    }

    public static <E extends IPooledObject> E tryRelease(E iPooledObject) {
        if (iPooledObject != null && !iPooledObject.isFree()) {
            iPooledObject.release();
        }

        return null;
    }

    public static <E extends IPooledObject> E[] tryRelease(E[] iPooledObject) {
        PZArrayUtil.forEach(iPooledObject, Pool::tryRelease);
        return null;
    }

    private static final class PoolStacks {
        final THashSet<IPooledObject> inUse = new THashSet<>();
        final List<IPooledObject> released = new ArrayList();

        PoolStacks() {
            this.inUse.setAutoCompactionFactor(0.0F);
        }
    }
}
